package DHT.Chord.OpenChord.DHTCommands;

import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.Set;
import java.util.Vector;

import DHT.Chord.OpenChord.DHTFurtherClass.Node;
import DHT.Chord.OpenChord.DHTFurtherClass.StringKey;

import de.uniba.wiai.lspi.chord.data.URL;
import de.uniba.wiai.lspi.chord.service.Chord;
import de.uniba.wiai.lspi.chord.service.ServiceException;

public class OpenChordCommandsImpl implements IOpenChordCommands{

	private Chord chord = null;
	
	//inicializa as propriedades a serem utilizadas
	private void SetProperties(){
		
		System.setProperty("log4j.properties.file", "log4j.properties");
		System.setProperty("de.uniba.wiai.lspi.chord.data.ID.number.of.displayed.bytes", "4");
		System.setProperty("de.uniba.wiai.lspi.chord.data.ID.displayed.representation", "2");
		System.setProperty("de.uniba.wiai.lspi.chord.service.impl.ChordImpl.successors", "2");
		System.setProperty("de.uniba.wiai.lspi.chord.service.impl.ChordImpl.AsyncThread.no", "10");
		System.setProperty("de.uniba.wiai.lspi.chord.service.impl.ChordImpl.StabilizeTask.start", "12");
		System.setProperty("de.uniba.wiai.lspi.chord.service.impl.ChordImpl.StabilizeTask.interval", "12");
		System.setProperty("de.uniba.wiai.lspi.chord.service.impl.ChordImpl.FixFingerTask.start", "0");
		System.setProperty("de.uniba.wiai.lspi.chord.service.impl.ChordImpl.FixFingerTask.interval", "12");
		System.setProperty("de.uniba.wiai.lspi.chord.service.impl.ChordImpl.CheckPredecessorTask.start", "6");
		System.setProperty("de.uniba.wiai.lspi.chord.service.impl.ChordImpl.CheckPredecessorTask.interval", "12");
		System.setProperty("de.uniba.wiai.lspi.chord.com.socket.InvocationThread.corepoolsize", "10");
		System.setProperty("de.uniba.wiai.lspi.chord.com.socket.InvocationThread.maxpoolsize", "50");
		System.setProperty("de.uniba.wiai.lspi.chord.com.socket.InvocationThread.keepalivetime", "20");
		
	}
	
	public void CreateDHT(int myport) {

		SetProperties();
		
		String protocol = URL.KNOWN_PROTOCOLS.get(URL.SOCKET_PROTOCOL );
		
		URL localURL = null;
		
		try {
			
			localURL = new URL (protocol+"://localhost:"+myport+"/");
			
		} catch ( MalformedURLException e){
			
			throw new RuntimeException (e);
			
		}
		
		chord = new de.uniba.wiai.lspi.chord.service.impl.ChordImpl();
		
		try {
			
			chord.create ( localURL );
			
		} catch ( ServiceException e) {
			
			throw new RuntimeException (" Could not create DHT !", e);
			
		}
		
	}

	@SuppressWarnings("unchecked")
	public Vector<Node> GetData(String key) {

		if(chord != null){
			
			StringKey myKey = new StringKey(key);
			
			Vector<Node> list = null;
			
			try{
				
				Set<Serializable> aux = null;
				
				aux = (Set<Serializable>)chord.retrieve(myKey);
				
				list = (Vector<Node>) aux.iterator().next();
			
			} catch( ServiceException e){
				
				e.printStackTrace();
				
			}
			return list;
			
		}
		return null;
		
	}

	//true se for efectuada
	public boolean JoinDHT(int myport, String bootIP, int bootport) {
		
		String protocol = URL.KNOWN_PROTOCOLS.get(URL.SOCKET_PROTOCOL );
		
		URL localURL = null;
		
		try {
			
			localURL = new URL (protocol+"://localhost:"+myport+"/");
			
		} catch ( MalformedURLException e){
			
			throw new RuntimeException (e);
			
		}

		URL bootstrapURL = null;
		
		try {
			
			bootstrapURL = new URL (protocol+"://"+bootIP+":"+bootport+"/");
		
		} catch ( MalformedURLException e){
			
			throw new RuntimeException (e);
		
		}
		
		chord = new de.uniba.wiai.lspi.chord.service.impl.ChordImpl();
		
		try {
			
			chord.join ( localURL , bootstrapURL );
			
			return true;
		
		} catch ( ServiceException e) {
			
			e.printStackTrace();
			
			return false;
			
			//throw new RuntimeException (" Could not join DHT !", e);
				
		}
		
	}

	public void LeaveDHT() {
		
		if(chord != null){
			
			try {
				
				chord.leave();
				
			} catch (ServiceException e) {
				
				e.printStackTrace();
				
			}
			
		}
		
	}

	public void PutData(String key, Vector<Node> list) {
			
		if(chord != null){
			
			StringKey myKey = new StringKey(key);
			
			try{
				
				chord.insert(myKey,list);
			
			} catch( ServiceException e){
				
				e.printStackTrace();
				
			}
			
		}
		
	}

	public void RemoveData(String key, Vector<Node> list) {
		
		if(chord != null){
			
			StringKey myKey = new StringKey(key);
			
			try{
				
				chord.remove(myKey, list);
			
			} catch( ServiceException e){
				
				e.printStackTrace();
				
			}
			
		}
		
	}

	
}
